#pragma once
#include <exception>

#include "inc_windows_h.hpp"
#include "memory.hpp"

namespace wxx
{
	void ensure_success_hr(HRESULT hr, IErrorInfo* info = 0) throw(...);
	void ensure_success_win32(BOOL result) throw(...);
	HANDLE ensure_success_win32(HANDLE result) throw(...);

	struct wxx_error : std::exception
	{
		virtual ~wxx_error() throw();
		virtual const char* what() const;

		HRESULT hr() const throw()
		{
			return m_hr;
		}

		static void __declspec(noreturn) throw_hr(HRESULT hr, IErrorInfo* info = 0)
		{
			if (hr == E_OUTOFMEMORY)
			{
				throw std::bad_alloc();
			}

			throw wxx::wxx_error(hr, info);
		}

		static void __declspec(noreturn) throw_last_win32() 
		{
			throw_hr(HRESULT_FROM_WIN32(::GetLastError()));
		}

	private:

		HRESULT     m_hr;
		IErrorInfo* m_info;

		mutable const char * m_what; // HLOCAL

		explicit wxx_error(HRESULT hr, IErrorInfo* info)
			: m_hr(hr)
			, m_info(info)
			, m_what(NULL)
		{
			if (m_info)
			{
				m_info->AddRef();
			}
		}

		static const char* format_system_message(HRESULT hr);
	};
};